package workers;

import java.util.concurrent.BlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.SwingWorker;

import model.Software;
import workerUIs.StepFrame;
import workflow.IEventListener;
import workflow.SoftwareDevelopmentWorkflow;
import workflow.WorkflowEvent;
import workflow.WorkflowEvent.EventType;

public abstract class AbstractStepSwingWorker extends
		SwingWorker<Software, Void> {

	protected Logger logger = Logger.getLogger(AbstractStepSwingWorker.class.getCanonicalName());
	
	protected Software software;
	protected final StepFrame frame;
	protected final StepFrame nextFrame;
	protected final BlockingQueue<Software> inputQueue;
	protected final BlockingQueue<Software> outputQueue;
	protected final IEventListener listener;
	protected Long delay;
	
	public AbstractStepSwingWorker(final StepFrame frame, final BlockingQueue<Software> inputQueue, final BlockingQueue<Software> outputQueue, final StepFrame nextFrame, final IEventListener listener) {
		this.frame = frame;
		this.nextFrame = nextFrame;
		this.inputQueue = inputQueue;
		this.outputQueue = outputQueue;
		this.listener = listener;
		try {
			String delayText = frame.getMsField().getText();
			if (delayText == null || delayText.isEmpty()) {
				this.delay = 0L;
			} else {
				this.delay = Long.valueOf(delayText);
			}
		} catch (Exception e) {
			logger.log(Level.SEVERE, "Exception when parsing delay value " + getClass().getName() + ": " + e.getMessage());
			cancel(true);
		}
	}
	
	@Override
	protected Software doInBackground() throws Exception {
		try {
			this.software = this.inputQueue.take();
			if (listener != null) listener.onEvent(WorkflowEvent.createEvent(this.software.getId(), getTaskName(), EventType.START));
			if (delay > 0L) {
				Thread.sleep(delay);
			}
			if (this.software != null) {
				this.software = doStep(this.software);
				this.outputQueue.put(this.software);
			}
			if (listener != null) listener.onEvent(WorkflowEvent.createEvent(this.software.getId(), getTaskName(), EventType.END));
			return this.software;
		} catch (Exception e) {
			e.printStackTrace();
			logger.log(Level.SEVERE, "Exception when executing step: " + getClass().getName() + ": " + e.getMessage());
		}
		return null;
	}
	protected abstract String getTaskName();
	
	protected abstract Software doStep(Software software);

	public BlockingQueue<Software> getInputQueue() {
		return inputQueue;
	}
	
	public StepFrame getNextFrame() {
		return nextFrame;
	}
	
	public BlockingQueue<Software> getOutputQueue() {
		return outputQueue;
	}
	
	public Software getSoftware() {
		return software;
	}

	public StepFrame getFrame() {
		return frame;
	}

	public void setSoftware(Software software) {
		this.software = software;
	}
	
	@Override
	protected void done() {
		if (this.inputQueue != null && inputQueue.isEmpty()) {
			getFrame().getNextButton().setEnabled(false);
		}
		String previousStepString = this.frame.getTextArea().getText();
		if (this.software != null) {
			this.frame.getTextArea().setText(previousStepString + "\n--------------\n" + this.software.toString());
		} else {
			this.frame.getTextArea().setText(previousStepString + "\n--------------\n" + "Software NULL!");
		}
		if (this.nextFrame != null) {
			this.nextFrame.getNextButton().setEnabled(true);
			if (SoftwareDevelopmentWorkflow.automaticMode) {
				this.nextFrame.getNextButton().doClick();	
			}			
		}
	}
}
